package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.fasterxml.jackson.databind.node.POJONode;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.DownOrUpDto;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.service.WmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import springfox.documentation.spring.web.json.Json;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description <p>自媒体图文内容信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    /**
     * 发表文章：草稿、提交待审核
     * @param draft 是否为草稿
     * @param dtoSave
     * @return
     */
    @Override
    @Transactional
    public void submit(boolean draft, WmNewsDtoSave dtoSave) {
        LocalDateTime now = LocalDateTime.now();
        //一、添加文章信息到数据
        //    1. new Pojo()
        WmNews pojo = new WmNews();
        BeanUtils.copyProperties(dtoSave,pojo);
        //    2. 设置属性的值
        pojo.setUserId(RequestContextUtil.getUserId());
        if (null == dtoSave.getPublishTime()){
            pojo.setPublishTime(now);
        }
        if (!draft){
            // 提交待审核
            pojo.setSubmitedTime(now);
        }
        pojo.setStatus(draft?0:1);
        // 封面图片如果有值，则以逗号分割
        if (!CollectionUtils.isEmpty(dtoSave.getImages())){
            String imageStr = String.join(",", dtoSave.getImages());
            pojo.setImages(imageStr);
        }
        pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);
        //      2.1 获取type的值 当type=-1 前端自动
        //      2.2 提取文章内容中的图片
        //      2.3 根据图片的数量 来设置type的值，还有封面
        //        count=0 设置type=无图，封面为""
        //        count<3 设置type=单图, 封面为取第一张图片
        //        count>=3 设置type=多图,封面取前3张图片
        setWmNewsType(dtoSave,pojo);
        //    3. save方法, 获取新增文章id
        if (null == dtoSave.getId()){
            save(pojo);
            pojo.setCreatedTime(now);
        }else {
            //更新
            updateById(pojo);
            // 删除旧的文章与素材关系. 多对多关系维护时，采用先删除旧关系，再添加新关系
            removeWmNewsMaterialRelationship(pojo.getId());
            //  二、添加文章与素材的关系
            addWmNewsMaterialRelationship(pojo);
            //     1. 内容中的图片（list）、封面图片(list)提取它们的图片地址
            //     2. 通过图片地址查询素材表，得到素材的id
            //     3. 构建pojo
            //     4. 设置属性
            //     5. 保存
            //  事务控制
        }
    }
    /**
     * 删除文章与素材的关系
     * @param id
     */
    private void removeWmNewsMaterialRelationship(Long id) {
        wmNewsMaterialMapper.deleteByMap(Collections.singletonMap("news_id", id));
    }

    /**
     * 文章列表 分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResultVo findPage(WmNewsPageReqDto dto) {
        //1. 构建分页参数
        Page<WmNews> pageInfo = new Page<>(dto.getPage(),dto.getSize());
        //2. 构建分页条件
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.eq(WmNews::getUserId,RequestContextUtil.getUserId());
        lqw.eq(null !=dto.getStatus(),WmNews::getStatus,dto.getStatus());
        lqw.like(null!=dto.getKeyword(),WmNews::getTitle,dto.getKeyword());
        lqw.eq(null!=dto.getChannelId(), WmNews::getChannelId,dto.getChannelId());
        lqw.le(null!=dto.getEndPubDate(),WmNews::getPublishTime,dto.getEndPubDate());
        //3. 执行查询
        page(pageInfo,lqw);
        //4. 构建分页结果返回
        return PageResultVo.pageResult(dto.getPage(),dto.getSize(),pageInfo.getTotal(),pageInfo.getRecords());
    }

    /**
     * 查询登录用户发表的文章
     *
     * @param id
     * @return
     */
    @Override
    public WmNews findById(Long id) {

        return query().eq("id",id).eq("user_id",RequestContextUtil.getUserId()).one();

    }

    /**
     * 通过id删除
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        //1. 通过id查询
        WmNews wmNews = findById(id);
        if (null ==wmNews){
            throw  new LeadNewsException("所查询文章不存在!");
        }
        //2. 判断状态，不9,不上架才能删除
        if (wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED ||
                wmNews.getStatus() == BusinessConstants.WmNewsConstants.ENABLE_ON){
            throw new LeadNewsException("文章已上架或已发布，不能删除");
        }
        //3. 删除文章表记录
        removeById(id);
        //4. 删除关系表记录
        removeWmNewsMaterialRelationship(id);
        //5. 事务控制
    }

    /**
     * 文章上下架处理
     *
     * @param dto
     */
    @Override
    public void downOruP(DownOrUpDto dto) {
        //1. 通过id查询
        WmNews wmNews = findById(dto.getId());
        if (null == wmNews){
            // 防止 不正常操作。直接用postman
            throw new LeadNewsException("所查询的文章不存在!");
        }
        //2. 判断状态是否为9，不为9就报错
        if (wmNews.getStatus()!=BusinessConstants.WmNewsConstants.STATUS_PUBLISHED){
            throw new LeadNewsException("文章状态不为已发布，不能上架或下架!");
        }
        //3. 判断操作类型, 为什么不使用上面查到wmNews来做更新，而非要自己new updatePojo

        //原因：MP下，通过updateById方法时,对象属性值不为空，则把这个属性放到更新语句中，update wm_news set title=有值,content= 有值
        //                              对象属性值为空, 则不会把这个属性放到更新语句中 title=null, update 不会出title
        //    2： 在并发, 有2个请求更新同一篇文章。
        // 李四    修改title=abc wmNews(查出来，属性都有值, enable=0) 执行更新： 属性有值则更新  enable=0， title=abc
        // 张三    改为上架， enable=1  wmNews(查出来，属性都有值,title=bbb) 先执行更新: enable=1 title=bbb

        // 更新数据时，只更新必须更新的字段，无关的字段，不要出现在update语句里.
        WmNews updatePojo = new WmNews();
        updatePojo.setId(dto.getId());
        if (dto.getEnable()==BusinessConstants.WmNewsConstants.ENABLE_OFF){
            //3.1 下架，更新enable值，还更新status=0
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_DRAFT);
        }
        //3.2 更新enable的值
        updatePojo.setEnable(dto.getEnable());
        updateById(updatePojo);
    }
    //3.2 更新enable的值


    /**
     * 添加文章与素材的关系
     * @param pojo
     */
    private void addWmNewsMaterialRelationship(WmNews pojo) {
        //1. 内容中的图片（list）、封面图片(list)提取它们的图片地址
        Set<String> pics =new HashSet<String>();
        // 封面的图片且去前缀
        List<String> coverList = new ArrayList<>();
        // 处理的封面图片
        if (!StringUtils.isEmpty(pojo.getArticleId())){
            // 封面的图片数组
            String[] coverArr = pojo.getImages().split(",");
            // 封面图片集合，已去前缀
            coverList = Arrays.stream(coverArr).map(this::removePrefix).collect(Collectors.toList());
            pics.addAll(coverList);
        }
        // 处理内容图片
        String content = pojo.getContent();
        // 内容中的图片且去了前缀
        List<String> contentImageList = new ArrayList<>();
        if (!StringUtils.isEmpty(content)){
            //内容是一个json字符串
            // contentList 包含了文本也包含了图片
            List<WmNewsContentNodeDto> contentList = JSON.parseArray(content, WmNewsContentNodeDto.class);
            // 只要图片
           contentImageList = contentList.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                   .map(WmNewsContentNodeDto::getValue).map(this::removePrefix).collect(Collectors.toList());
           pics.addAll(contentImageList);
        }
        //2. 通过图片地址查询素材表，得到素材的id
        LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
        lqw.in(WmMaterial::getUrl,pics); // url相同
        List<WmMaterial>wmMaterialList =wmMaterialMapper.selectList(lqw);
        // map<url, id> map.get(coverUrl)
        Map<String, Long> materialMap = wmMaterialList.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        // 封面中的图片
        addNewsMaterialRelationship(pojo.getId(), coverList, materialMap,BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);
        // 内容中的图片
        addNewsMaterialRelationship(pojo.getId(),contentImageList,materialMap,BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);
    }

    private void addNewsMaterialRelationship(Long wmNewsId, List<String> coverList, Map<String, Long> materialMap, int type) {
        for (int i = 0; i < coverList.size(); i++) {
            //3. 构建pojo
            WmNewsMaterial nm = new WmNewsMaterial();
            //4. 设置属性
            nm.setType(type);
            nm.setOrd(i+1);
            nm.setNewsId(wmNewsId);

                        /*for (WmMaterial material : wmMaterialList) {
                String coverUrl = coverList.get(i);
                // 如果url地址相同
                if (material.getUrl().equals(coverUrl)) {
                    nm.setMaterialId(material.getId());
                    break;
                }
            }*/
            //5. 保存
            wmNewsMaterialMapper.insert(nm);
        }
    }

    /**
     * 如果封面是自动时的处理
     * @param dtoSave
     * @param pojo
     */
    private void setWmNewsType(WmNewsDtoSave dtoSave, WmNews pojo) {
        //2.1 获取type的值 当type=-1 前端自动
        if (dtoSave.getType() == -1){
            //2.2 提取文章内容中的图片
            String content = dtoSave.getContent();
            if (!StringUtils.isEmpty(content)) {
                //内容是一个json字符串
                // contentList 包含了文本也包含了图片
                List<WmNewsContentNodeDto> contentList =JSON.parseArray(content,WmNewsContentNodeDto.class);
                // 只要图片
                List<String> imageList =contentList.stream().filter(n ->BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                        .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
                //2.3 根据图片的数量 来设置type的值，还有封面
                int count = imageList.size();
                //  count=0 设置type=无图，封面为""
                if (count ==0){
                    pojo.setImages("");
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                }else if (count < 3){
                    //  count<3 设置type=单图, 封面为取第一张图片
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                    pojo.setImages(imageList.get(0));
                }else {
                    //  count>=3 设置type=多图,封面取前3张图片
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                    // 取前3张, 并且用逗号分割拼接
                    String images = imageList.stream().limit(3).collect(Collectors.joining(","));
                    pojo.setImages(images);
                    /*
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < 3; i++) {
                        sb.append(imageList.get(i)).append(",");
                    }
                    sb.setLength(sb.length()-1);*/
                }
            }else {
                pojo.setImages("");
                pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
            }
        }
    }
    /*
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a.jpg");
        list.add("b.jpg");
        System.out.println(String.join(",", list));
    }*/
    private String removePrefix(String url){
        //http://192.168.211.128:8080/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://192.168.211.128/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://127.0.0.1/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }
}
